<?php
/**
 * Created by PhpStorm.
 * Script Name: Bot.php
 * Create: 2023/2/10 10:35
 * Description:
 * Author: fudaoji<fdj@kuryun.cn>
 */

namespace plugin\wechat\app\service;


use app\common\service\Tenant as TenantService;
use plugin\wechat\app\model\Bot as BotM;
use plugin\wechat\app\service\BotSetting as SettingService;
use plugin\wechat\extend\WxBot\Client;
use plugin\wechat\extend\WxBot\Driver\Cat;
use plugin\wechat\extend\WxBot\Driver\My;
use plugin\wechat\extend\WxBot\Driver\Mycom;
use plugin\wechat\extend\WxBot\Driver\Qianxun;
use plugin\wechat\extend\WxBot\Driver\Vlw;
use plugin\wechat\extend\WxBot\Driver\Webgo;
use plugin\wechat\extend\WxBot\Driver\Wxwork;

class Bot extends Common
{
    const PROTOCOL_WEB = 'webgo';
    const PROTOCOL_CAT = 'cat';
    const PROTOCOL_VLW = 'vlw';
    const PROTOCOL_WXWORK = 'wxwork'; //企业微信
    const PROTOCOL_MY = 'my'; //西瓜个微
    const PROTOCOL_MYCOM = 'mycom'; //西瓜企微
    const PROTOCOL_QXUN = 'qianxun'; //千寻个微
    const PROTOCOL_XBOT = 'xbot'; //XBOT个微

    const FRIEND = 'friend';
    const GROUP = 'group';
    const MP = 'mp';

    const EVENT_GROUP_ESTABLISH = 'EventGroupEstablish'; //创建新群
    const EVENT_GROUP_MEMBER_ADD = 'EventGroupMemberAdd'; //群人员减少
    const EVENT_GROUP_MEMBER_DEC = 'EventGroupMemberDecrease'; //群人员减少
    const EVENT_FRIEND_VERIFY = 'EventFriendVerify'; //好友请求事件
    const EVENT_DEVICE = "EventDeviceCallback"; //设备回调事件
    const EVENT_LOGIN = "EventLogin"; //登录、退出
    const EVENT_LOGOUT = "EventLogout"; //退出
    const EVENT_GROUP_CHAT = "EventGroupChat"; //群聊事件
    const EVENT_PRIVATE_CHAT = "EventPrivateChat"; //私聊消息事件
    const EVENT_RECEIVE_TRANSFER = 'EventReceivedTransfer'; //收到转账
    const EVENT_SCAN_CASH_MONEY = 'EventScanCashMoney'; //面对面付款
    const EVENT_LOGIN_CODE = 'EventLoginCode'; //接收登录二维码信息
    const EVENT_CONNECTED = 'EventConnected';

    const MSG_TEXT = 1; //文本消息
    const MSG_IMG = 3; //图片消息
    const MSG_VOICE = 34; //语音消息
    const MSG_VIDEO = 43; //视频
    const MSG_LINK = 49; //分享链接
    const MSG_FILE = 2004;  //文件消息
    const MSG_EMOTICON = 47;   // 表情消息
    const MSG_CARD = 42; //名片消息
    const MSG_LOCATION= 48;    // 地理位置消息
    const MSG_TRANSFER = 2000;  //转账消息
    const MSG_RED = 2001;  //红包消息
    const MSG_APP = 2002;  // 小程序消息
    const MSG_GROUPINVITE = 2003;  //群邀请
    const MSG_VERIFY = 37;    // 好友验证
    const MSG_SYS = 10000; // 系统消息
    const MSG_RECALLED = 2005;  // 消息撤回
    const MSG_OTHER = 0; // 其他消息

    //添加好友场景值
    const SCENE_WXNUM = 3; //微xin号搜索
    const SCENE_QQ = 12;  //QQ号搜索
    const SCENE_GROUP = 14; //群聊
    const SCENE_CONTACT = 15; //手机通讯录
    const SCENE_CARD = 17; //名片分享
    const SCENE_NEAR = 18; //附近人
    const SCENE_SHAKE = 29; //摇一摇
    const SCENE_SCAN = 30; //扫一扫

    /**
     * 员工所属bot条件
     * @param string $alias
     * @param array $tenant_info
     * @return array
     * Author: fudaoji<fdj@kuryun.cn>
     */
    static function tenantBotWhere($alias = '', $tenant_info = []){
        $alias = $alias ? $alias.'.' : '';
        $tenant_info = empty($tenant_info) ? TenantService::sessionTenantInfo() : $tenant_info;
        if(TenantService::isLeader($tenant_info)){
            $where = [['company_id','=',TenantService::getCompanyId($tenant_info)]];
        }else{
            $where = [['tenant_id','=', $tenant_info['id']]];
        }
        $bot_ids = BotM::where($where)->column('id');
        return [$alias . 'bot_id' , 'in', count($bot_ids) ? $bot_ids : [0]];
    }

    /**
     * 获取机器人列表[id =>title,]
     * @param int $company_id
     * @param array $map
     * @return array|mixed|\think\db\Query|\think\Model|null
     */
    static function getIdToTitle($company_id = 0, $map = []){
        empty($company_id) && $company_id = TenantService::getCompanyId();
        $query = BotM::where('company_id', $company_id);
        $map && $query = $query->where($map);
        return $query->column('title', 'id');
    }

    /**
     * 根据wxid获取bot信息
     * @param int $uin
     * @param int $company_id
     * @return array|mixed|\think\db\Query|\think\Model|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    static function getBotByUin($uin = 0, $company_id = 0){
        empty($company_id) && $company_id = TenantService::getCompanyId();
        return BotM::where([
            ['company_id','=', $company_id],
            ['uin', '=', $uin]
        ])
            ->find();
    }

    /**
     * 根据id获取bot信息
     * @param int $id
     * @param int $company_id
     * @return array|mixed|\think\db\Query|\think\Model|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    static function getBot($id = 0, $company_id = 0){
        empty($company_id) && $company_id = TenantService::getCompanyId();
        return BotM::where([
            ['company_id','=', $company_id],
            ['id', '=', $id]
        ])
            ->find();
    }

    /**
     * 获取机器人客户端
     * @param array $bot
     * @return Cat|Vlw|Wxwork|My
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    static function getRobotClient($bot = []){
        $options = ['app_key' => $bot['app_key'], 'base_uri' => $bot['url'], 'uuid' => $bot['uuid']];
        $config_save = SettingService::getSettings($bot['company_id'], 'save');
        !empty($config_save['step_time']) && $options['step_time'] = explode('-', $config_save['step_time']);
        return Client::getInstance($options, $bot['protocol'])->getBot();
    }

    /**
     *
     * @param array $params
     * @return string|array
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    static function getRobotInfo($params = []){
        /**
         * @var $bot_client Vlw|Cat|Wxwork|My|Qianxun
         */
        $bot_client = self::getRobotClient($params);
        switch ($params['protocol']){
            case self::PROTOCOL_XBOT:
                $return = $bot_client->getRobotInfo(['client_id' => $params['uuid']]);
                if($return['code'] && !empty($return['data'])){
                    $data = $return['data'];
                    return [
                        'wxid' => $data['wxid'],
                        'nickname' => $data['nickname'],
                        'username' => $data['account'],
                        'headimgurl' => $data['avatar'],
                        'uuid' => $params['uuid']
                    ];
                }else{
                    return $bot_client->getError();
                }
                break;
            case self::PROTOCOL_QXUN:
                $return = $bot_client->getRobotInfo(['robot_wxid' => $params['uin']]);
                if($return['code'] && !empty($return['data'])){
                    return $return['data'];
                }else{
                    return  $bot_client->getError();
                }
                break;
            case self::PROTOCOL_CAT:
                $return = $bot_client->getRobotList();
                if($return['code'] && !empty($return['data'])){
                    foreach ($return['data'] as $v){
                        if($v['wxid'] == $params['uin']){
                            $v['username'] = $v['wx_num'];
                            return $v;
                        }
                    }
                }else{
                    return  $bot_client->getError();
                }
                break;
            default:
                $return = $bot_client->getRobotList();
                if($return['code'] && !empty($return['ReturnJson'])){
                    foreach ($return['ReturnJson']['data'] as $v){
                        if($v['wxid'] == $params['uin']){
                            $v['nickname'] = $v['username'];
                            $v['username'] = $v['wx_num'];
                            $v['headimgurl'] = $v['wx_headimgurl'];
                            return $v;
                        }
                    }
                }else{
                    return  $bot_client->getError();
                }
                break;
        }
        return [];
    }

    /**
     * 登录码缓存
     * @param string $driver
     * @param string $host
     * @param null $data
     * @return mixed
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function cacheLoginCode($driver = 'xbot', $host = '',$data = null)
    {
        $key = md5("logincode-{$driver}-".$host);
        if($data !== null){
            return cache($key, $data, 300);
        }
        return cache($key);
    }

    /**
     * 消息类型
     * @param null $id
     * @return array|mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public static function msgTypes($id = null){
        $list = [
            self::MSG_TEXT => '文本',
            self::MSG_IMG => '图片',
            self::MSG_FILE => '文件',
            self::MSG_VOICE => '语音',
            self::MSG_VIDEO => '视频',
            self::MSG_LINK => '分享链接',
            self::MSG_EMOTICON => '动态表情',
            self::MSG_CARD => '微信名片',
            self::MSG_LOCATION => '地理位置',
            self::MSG_TRANSFER => '转账',
            self::MSG_RED => '红包',
            self::MSG_APP => '小程序',
            self::MSG_GROUPINVITE => '进群邀请',
            self::MSG_VERIFY => '加好友验证',
            self::MSG_RECALLED => '消息撤回',
            self::MSG_OTHER => '其他'
        ];
        return isset($list[$id]) ? $list[$id] : $list;
    }

    /**
     * 机器人协议
     * @param null $id
     * @return array|mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public static function protocols($id = null)
    {
        $list = [
            self::PROTOCOL_QXUN => '千寻个微',
            self::PROTOCOL_WEB => '网页版',
            self::PROTOCOL_MY => '西瓜个微',
            self::PROTOCOL_MYCOM => '西瓜企微',
            self::PROTOCOL_CAT => '可爱猫个微',
            self::PROTOCOL_VLW => 'VLW个微',
            self::PROTOCOL_WXWORK => 'VLW企微',
            self::PROTOCOL_XBOT => 'XBOT个微',
        ];
        return isset($list[$id]) ? $list[$id] : $list;
    }

    /**
     * 机器人协议
     * @param null $id
     * @return array|mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public static function webs($id = null)
    {
        $list = [
            self::PROTOCOL_WEB => 'go-wxbot',
        ];
        return isset($list[$id]) ? $list[$id] : $list;
    }

    /**
     * 机器人hook协议
     * @param null $id
     * @return array|mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public static function hooks($id = null)
    {
        $list = [
            self::PROTOCOL_MY => '西瓜个微',
            self::PROTOCOL_MYCOM => '西瓜企微',
            self::PROTOCOL_CAT => '可爱猫个微'
        ];
        return isset($list[$id]) ? $list[$id] : $list;
    }

    /**
     * 支持扫码登录的机器人协议
     * @param null $id
     * @return array|mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public static function canScan($id = null)
    {
        $list = [
            self::PROTOCOL_MY => '我的个微',
            self::PROTOCOL_XBOT=> 'XBot个微'
        ];
        return isset($list[$id]) ? $list[$id] : $list;
    }
}